﻿// -------------------------------------------------------------------------
//    @FileName         :    ItemTest.cpp
//    @Author           :    gaoyi
//    @Date             :    2025/1/20
//    @Email            :    445267987@qq.com
//    @Module           :    ItemTest
//
// -------------------------------------------------------------------------

#include "BagSystemTestBase.h"
#include "MockItemDesc.h"

/**
 * @brief 物品测试类
 * 
 * 测试物品相关的功能：
 * - 物品创建和初始化
 * - 物品属性管理
 * - 物品序列化和反序列化
 * - 物品比较和排序
 * - 物品堆叠和合并
 */
class ItemTest : public BagSystemTestBase {
protected:
    void SetUp() override {
        BagSystemTestBase::SetUp();
    }
    
    void TearDown() override {
        BagSystemTestBase::TearDown();
    }
};

// === 物品基础功能测试 ===

/**
 * @brief 测试物品创建和初始化
 */
TEST_F(ItemTest, ItemCreationTest) {
    // 创建普通物品
    NFGridItem normalItem = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1, TestQuality::WHITE, false);
    ASSERT_ITEM_VALID(normalItem);
    VerifyItemProperties(normalItem, TestItemIds::NORMAL_ITEM_1, 1, TestQuality::WHITE);
    ASSERT_FALSE(normalItem.IsBind()) << "普通物品不应该绑定";
    
    // 创建堆叠物品
    NFGridItem stackableItem = CreateTestItem(TestItemIds::STACKABLE_ARROW, 100, TestQuality::WHITE, false);
    ASSERT_ITEM_VALID(stackableItem);
    VerifyItemProperties(stackableItem, TestItemIds::STACKABLE_ARROW, 100, TestQuality::WHITE);
    ASSERT_EQ(stackableItem.GetNumber(), 100) << "堆叠物品数量不正确";
    
    // 创建绑定物品
    NFGridItem bindItem = CreateTestItem(TestItemIds::UNIQUE_QUEST_ITEM, 1, TestQuality::BLUE, true);
    ASSERT_ITEM_VALID(bindItem);
    ASSERT_TRUE(bindItem.IsBind()) << "任务物品应该绑定";
    
    // 创建装备
    NFGridItem equipItem = CreateTestEquip(TestItemIds::WEAPON_SWORD, TestQuality::GREEN, 5);
    ASSERT_ITEM_VALID(equipItem);
    VerifyItemProperties(equipItem, TestItemIds::WEAPON_SWORD, 1, TestQuality::GREEN);
}

/**
 * @brief 测试物品属性设置和获取
 */
TEST_F(ItemTest, ItemPropertyTest) {
    NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    
    // 测试数量设置
    item.SetNumber(5);
    ASSERT_EQ(item.GetNumber(), 5) << "设置物品数量失败";
    
    item.AddNumber(3);
    ASSERT_EQ(item.GetNumber(), 8) << "增加物品数量失败";
    
    item.DecNumber(2);
    ASSERT_EQ(item.GetNumber(), 6) << "减少物品数量失败";
    
    // 测试品质设置
    item.SetQuality(TestQuality::BLUE);
    ASSERT_EQ(item.GetQuality(), TestQuality::BLUE) << "设置物品品质失败";
    
    // 测试绑定状态
    ASSERT_FALSE(item.IsBind()) << "初始状态不应该绑定";
    item.SetBind(true);
    ASSERT_TRUE(item.IsBind()) << "设置绑定失败";
    item.SetBind(false);
    ASSERT_FALSE(item.IsBind()) << "取消绑定失败";
    
    // 测试UUID
    uint64_t originalUUID = item.GetUUID();
    ASSERT_GT(originalUUID, 0) << "UUID应该大于0";
    
    uint64_t newUUID = 12345;
    item.SetUUID(newUUID);
    ASSERT_EQ(item.GetUUID(), newUUID) << "设置UUID失败";
}

/**
 * @brief 测试物品时效性
 */
TEST_F(ItemTest, ItemEffectTimeTest) {
    NFGridItem item = CreateTestItem(TestItemIds::POTION_HP, 1);
    
    // 设置生效时间
    uint32_t currentTime = static_cast<uint32_t>(time(nullptr));
    uint32_t expireTime = currentTime + 3600; // 1小时后过期
    
    item.SetEffectTime(expireTime);
    ASSERT_EQ(item.GetEffectTime(), expireTime) << "设置生效时间失败";
    
    // 测试是否过期
    ASSERT_FALSE(item.IsEffectTimeOut()) << "物品不应该过期";
    
    // 设置已过期时间
    uint32_t pastTime = currentTime - 3600; // 1小时前已过期
    item.SetEffectTime(pastTime);
    ASSERT_TRUE(item.IsEffectTimeOut()) << "物品应该已过期";
}

/**
 * @brief 测试物品交易冷却
 */
TEST_F(ItemTest, ItemTradeCoolDownTest) {
    NFGridItem item = CreateTestItem(TestItemIds::WEAPON_SWORD, 1);
    
    // 设置交易冷却时间
    uint32_t currentTime = static_cast<uint32_t>(time(nullptr));
    uint32_t coolDownTime = currentTime + 1800; // 30分钟冷却
    
    item.SetTradeCoolDown(coolDownTime);
    ASSERT_EQ(item.GetTradeCoolDown(), coolDownTime) << "设置交易冷却时间失败";
}

/**
 * @brief 测试物品格子索引
 */
TEST_F(ItemTest, ItemGridIndexTest) {
    NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    
    // 测试初始格子索引
    ASSERT_EQ(item.GetGridIndex(), INVALID_ID) << "初始格子索引应该为INVALID_ID";
    
    // 设置格子索引
    item.SetGridIndex(5);
    ASSERT_EQ(item.GetGridIndex(), 5) << "设置格子索引失败";
    
    // 重置格子索引
    item.SetGridIndex(INVALID_ID);
    ASSERT_EQ(item.GetGridIndex(), INVALID_ID) << "重置格子索引失败";
}

// === 物品序列化测试 ===

/**
 * @brief 测试物品序列化和反序列化
 */
TEST_F(ItemTest, ItemSerializationTest) {
    // 创建原始物品
    NFGridItem originalItem = CreateTestItem(TestItemIds::WEAPON_SWORD, 1, TestQuality::GREEN, true);
    originalItem.SetGridIndex(3);
    originalItem.SetEffectTime(static_cast<uint32_t>(time(nullptr)) + 3600);
    originalItem.SetTradeCoolDown(static_cast<uint32_t>(time(nullptr)) + 1800);
    
    // 序列化到PB
    proto_ff::ItemGridCSData pbData;
    int serializeResult = originalItem.ToPb(&pbData);
    ASSERT_EQ(serializeResult, 0) << "序列化物品失败";
    
    // 验证PB数据
    ASSERT_EQ(pbData.base().id(), TestItemIds::WEAPON_SWORD) << "序列化后物品ID不正确";
    ASSERT_EQ(pbData.base().value(), 1) << "序列化后物品数量不正确";
    ASSERT_EQ(pbData.index(), 3) << "序列化后格子索引不正确";
    
    // 反序列化
    NFGridItem deserializedItem;
    int deserializeResult = deserializedItem.FromPb(pbData);
    ASSERT_EQ(deserializeResult, 0) << "反序列化物品失败";
    
    // 验证反序列化结果
    VerifyItemProperties(deserializedItem, TestItemIds::WEAPON_SWORD, 1, TestQuality::GREEN);
    ASSERT_EQ(deserializedItem.GetGridIndex(), 3) << "反序列化格子索引不正确";
    ASSERT_EQ(deserializedItem.GetUUID(), originalItem.GetUUID()) << "反序列化UUID不正确";
    ASSERT_EQ(deserializedItem.IsBind(), originalItem.IsBind()) << "反序列化绑定状态不正确";
}

// === 物品比较和排序测试 ===

/**
 * @brief 测试物品比较
 */
TEST_F(ItemTest, ItemComparisonTest) {
    // 创建相同的物品
    NFGridItem item1 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 5, TestQuality::WHITE, false);
    NFGridItem item2 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 3, TestQuality::WHITE, false);
    
    // 测试相同物品ID的比较
    ASSERT_TRUE(NFItemUtil::IsSameItem(item1.GetItemBase(), item2.GetItemBase())) 
        << "相同物品ID应该被认为是相同物品";
    
    // 创建不同的物品
    NFGridItem item3 = CreateTestItem(TestItemIds::NORMAL_ITEM_2, 1, TestQuality::WHITE, false);
    ASSERT_FALSE(NFItemUtil::IsSameItem(item1.GetItemBase(), item3.GetItemBase())) 
        << "不同物品ID应该被认为是不同物品";
    
    // 测试绑定状态影响
    NFGridItem bindItem1 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1, TestQuality::WHITE, true);
    NFGridItem bindItem2 = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1, TestQuality::WHITE, false);
    ASSERT_FALSE(NFItemUtil::IsSameItem(bindItem1.GetItemBase(), bindItem2.GetItemBase())) 
        << "绑定状态不同的物品应该被认为是不同物品";
}

/**
 * @brief 测试物品排序
 */
TEST_F(ItemTest, ItemSortingTest) {
    // 创建物品列表
    std::vector<NFGridItem> items;
    items.push_back(CreateTestItem(TestItemIds::MATERIAL_WOOD, 50, TestQuality::WHITE));
    items.push_back(CreateTestItem(TestItemIds::WEAPON_SWORD, 1, TestQuality::GREEN));
    items.push_back(CreateTestItem(TestItemIds::POTION_HP, 20, TestQuality::WHITE));
    items.push_back(CreateTestItem(TestItemIds::ARMOR_HELMET, 1, TestQuality::BLUE));
    
    // 排序前验证
    ASSERT_EQ(items[0].GetItemID(), TestItemIds::MATERIAL_WOOD) << "排序前第一个物品ID不正确";
    
    // 执行排序
    std::sort(items.begin(), items.end(), NFItemUtil::CompareGridItem);
    
    // 验证排序结果 - 这里需要根据实际的排序规则来验证
    // 通常装备类物品优先级较高，品质高的优先级较高
    bool sortedCorrectly = true;
    for (size_t i = 1; i < items.size(); ++i) {
        // 这里的比较逻辑需要根据实际的排序实现来调整
        if (!NFItemUtil::CompareGridItem(items[i-1], items[i])) {
            sortedCorrectly = false;
            break;
        }
    }
    ASSERT_TRUE(sortedCorrectly) << "物品排序不正确";
}

// === 物品堆叠测试 ===

/**
 * @brief 测试物品堆叠
 */
TEST_F(ItemTest, ItemStackingTest) {
    // 创建可堆叠物品
    NFGridItem stackItem1 = CreateTestItem(TestItemIds::STACKABLE_ARROW, 50, TestQuality::WHITE, false);
    NFGridItem stackItem2 = CreateTestItem(TestItemIds::STACKABLE_ARROW, 30, TestQuality::WHITE, false);
    
    // 测试堆叠条件
    ASSERT_TRUE(NFItemUtil::IsSameItem(stackItem1.GetItemBase(), stackItem2.GetItemBase())) 
        << "相同的可堆叠物品应该可以堆叠";
    
    // 模拟堆叠操作（实际的堆叠逻辑在背包管理器中）
    int totalCount = stackItem1.GetNumber() + stackItem2.GetNumber();
    stackItem1.SetNumber(totalCount);
    
    ASSERT_EQ(stackItem1.GetNumber(), 80) << "堆叠后数量不正确";
    
    // 测试不同绑定状态的物品不能堆叠
    NFGridItem bindStackItem = CreateTestItem(TestItemIds::STACKABLE_ARROW, 20, TestQuality::WHITE, true);
    ASSERT_FALSE(NFItemUtil::IsSameItem(stackItem1.GetItemBase(), bindStackItem.GetItemBase())) 
        << "绑定状态不同的物品不应该可以堆叠";
}

// === 物品工具函数测试 ===

/**
 * @brief 测试物品工具函数
 */
TEST_F(ItemTest, ItemUtilityTest) {
    // 测试空物品判断
    NFGridItem emptyItem;
    ASSERT_TRUE(NFItemUtil::IsEmptyGrid(emptyItem)) << "空物品应该被识别为空";
    
    NFGridItem validItem = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    ASSERT_FALSE(NFItemUtil::IsEmptyGrid(validItem)) << "有效物品不应该被识别为空";
    
    // 测试物品类型判断
    ASSERT_TRUE(NFItemUtil::IsNormalItem(proto_ff::EN_ITEM_TYPE_NORMAL)) << "普通物品类型判断错误";
    ASSERT_FALSE(NFItemUtil::IsNormalItem(proto_ff::EN_ITEM_TYPE_EQUIP)) << "装备不应该被认为是普通物品";
    
    // 测试UUID物品判断
    ASSERT_TRUE(NFItemUtil::IsUUIDItem(proto_ff::EN_ITEM_TYPE_EQUIP)) << "装备应该需要UUID";
    ASSERT_FALSE(NFItemUtil::IsUUIDItem(proto_ff::EN_ITEM_TYPE_NORMAL)) << "普通物品通常不需要UUID";
}

/**
 * @brief 测试物品重置和清空
 */
TEST_F(ItemTest, ItemResetTest) {
    // 创建有效物品
    NFGridItem item = CreateTestItem(TestItemIds::WEAPON_SWORD, 1, TestQuality::GREEN, true);
    item.SetGridIndex(5);
    
    // 验证物品有效
    ASSERT_ITEM_VALID(item);
    ASSERT_EQ(item.GetGridIndex(), 5) << "格子索引应该为5";
    
    // 清空物品
    item.SetEmpty();
    ASSERT_ITEM_EMPTY(item) << "清空后物品应该为空";
    ASSERT_EQ(item.GetGridIndex(), INVALID_ID) << "清空后格子索引应该为INVALID_ID";
    
    // 重置物品
    item = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    item.Reset();
    ASSERT_ITEM_EMPTY(item) << "重置后物品应该为空";
}

/**
 * @brief 测试物品哈希
 */
TEST_F(ItemTest, ItemHashTest) {
    // 创建物品哈希对象
    NFItemHash hash1, hash2;
    hash1.itemId = TestItemIds::NORMAL_ITEM_1;
    hash1.quality = TestQuality::WHITE;
    hash1.bind = false;
    
    hash2.itemId = TestItemIds::NORMAL_ITEM_1;
    hash2.quality = TestQuality::WHITE;
    hash2.bind = false;
    
    // 测试相同哈希
    std::hash<NFItemHash> hasher;
    ASSERT_EQ(hasher(hash1), hasher(hash2)) << "相同属性的物品哈希应该相同";
    
    // 测试不同哈希
    hash2.bind = true;
    ASSERT_NE(hasher(hash1), hasher(hash2)) << "不同属性的物品哈希应该不同";
} 